package com.zjw.socket.demo.starter.buffer;

import com.zjw.socket.demo.starter.annotation.NonNull;
import com.zjw.socket.demo.starter.annotation.core.BufferHandler;
import com.zjw.socket.demo.starter.config.ApplicationConfig;
import com.zjw.socket.demo.starter.core.ioc.IOCBeanInfo;
import com.zjw.socket.demo.starter.core.ioc.IOCObserver;
import com.zjw.socket.demo.starter.core.ioc.IOCScope;
import com.zjw.socket.demo.starter.utils.LogUtils;
import com.zjw.socket.demo.starter.core.Reflector;
import com.zjw.socket.demo.starter.utils.ThreadPool;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetServer;
import io.vertx.core.net.NetSocket;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Buffer处理分发器
 */
public final class BufferDispatcher {

  private static final String TAG = "BufferDispatcher";
  private static final Map<Class<?>, Integer> bufferHandlers = new ConcurrentHashMap<>();
  private static final List<IBufferHandler> bufferHandlerList = new CopyOnWriteArrayList<>();

  /**
   * 初始化IBufferHandler并保存到 bufferHandlers中
   */
  public static void dispatchBufferHandler(NetServer netServer) {
    LogUtils.debug(TAG, "dispatch start");
    IOCScope.globalScope.registerRefreshObserver(new IOCObserver() {
      @Override
      public void onRefresh(Class<?> clazz) {
        if (!clazz.isAnnotationPresent(BufferHandler.class)) {
          return;
        }
        if (!Reflector.isSuperClassOrInterfaceImpl(clazz, IBufferHandler.class)) {
          throw new IllegalArgumentException("@BufferHandler type must implements IBufferHandler");
        }
        IBufferHandler o = (IBufferHandler) Reflector.instanceEmptyConstructor(clazz);
        if (o == null) {
          throw new IllegalArgumentException("IBufferHandler must have empty constructor");
        }

        o.onStart(netServer);

        IOCScope.globalScope.putBean(clazz, o);
        bufferHandlerList.add(o);
      }

      @Override
      public void onInject(IOCBeanInfo o) {

      }

      @Override
      public void onComplete() {
        bufferHandlerList.sort(Comparator.comparingInt(IBufferHandler::order));
      }
    });
  }

  /**
   * 获得Buffer
   */
  @NonNull
  @SuppressWarnings("unchecked")
  public static <T extends IBufferHandler> T optBufferHandler(Class<T> clazz) {
    Integer index = bufferHandlers.get(clazz);
    if (index == null) {
      throw new IllegalArgumentException("optBuffer null");
    }
    return (T) bufferHandlerList.get(index);
  }


  /**
   * 处理socket连接
   */
  public static void dispatchConnect(NetSocket socket) {
    LogUtils.debug(TAG, "receive connect " + socket);
    //处理收到的消息
    for (IBufferHandler bufferHandler : bufferHandlerList) {
      bufferHandler.onConnect(socket);
    }
    socket.handler(buffer -> BufferDispatcher.handleBuffer(socket, buffer));
  }

  /**
   * 处理buffer
   */
  public static void handleBuffer(NetSocket socket, Buffer buffer) {
    ThreadPool.submit(() -> {
      int bufferResult;
      for (IBufferHandler bufferHandler : bufferHandlerList) {
        bufferResult = bufferHandler.onBuffer(buffer, socket);
        if (bufferResult == IBufferHandler.BUFFER_RESULT_NEXT) {
          continue;
        }

        if (bufferResult == IBufferHandler.BUFFER_RESULT_INTERCEPTOR) {
          break;
        }

        if (bufferResult == IBufferHandler.BUFFER_RESULT_CLOSE) {
          socket.close();
          break;
        }
      }
    });

  }
}
